/**
 * 
 */
package xj.toolkit.bean.tlv.encode.encoders;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import xj.toolkit.bean.tlv.annotation.TlvType;
import xj.toolkit.bean.tlv.encode.TLVEncodeContext;
import xj.toolkit.bean.tlv.encode.TLVEncodeContextFactory;
import xj.toolkit.bean.tlv.encode.TLVEncoder;
import xj.toolkit.util.ByteUtils;

/**
 * @author marvin.ma
 * 
 */
public class ObjectArrayTLVEncoder implements TLVEncoder {

	private static final Logger LOG = LoggerFactory
			.getLogger(ObjectArrayTLVEncoder.class);

	private TLVEncodeContextFactory encodeContextFactory;

	public TLVEncodeContextFactory getEncodeContextFactory() {
		return encodeContextFactory;
	}

	public void setEncodeContextFactory(
			TLVEncodeContextFactory encodeContextFactory) {
		this.encodeContextFactory = encodeContextFactory;
	}

	/**
	 * 
	 * @see com.skymobi.util.Transformer#transform(java.lang.Object)
	 */
	public List<byte[]> encode(final Object src, final TLVEncodeContext ctx) {

		if (!ctx.getValueType().isArray()) {
			LOG.error("encode object's type {} is not array type",
					ctx.getValueType());
			return null;
		}

		final Field field = ctx.getValueField();
		final TlvType param = field.getAnnotation(TlvType.class);
		if (-1 == param.elementTag()) {
			LOG.error("Array field[{}]'s elementTag not define, ignore", field);
			return null;
		}

		final Class<?> elementType = ctx.getValueType().getComponentType();
		final TLVEncoder encoder = ctx.getEncoderRepository().getEncoderOf(
				elementType);
		if (null == encoder) {
			LOG.error("Array field[{}]/{} can not found encoder, ignore",
					field, elementType.getSimpleName());
			return null;
		}

		final List<byte[]> ret = new ArrayList<byte[]>();

		for (Object element : (Object[]) src) {
			final List<byte[]> dest = encoder.encode(element,
					encodeContextFactory
							.createEncodeContext(elementType, field));
			// tag
			ret.add(ctx.getNumberCodec().int2Bytes(param.elementTag(), 4));

			// len
			ret.add(ctx.getNumberCodec().int2Bytes(
					ByteUtils.totalByteSizeOf(dest), 4));

			ret.addAll(dest);
		}
		return ret;
	}

	public Class<?>[] getFieldType() {
		return new Class<?>[]{java.lang.Object[].class};
	}

}
